/**
 * 
 */
package cz.cuni.mff.abacs.burglar.logics;

import aStarLibrary.Node;
import cz.cuni.mff.abacs.burglar.logics.objects.BaseObject;
import cz.cuni.mff.abacs.burglar.logics.objects.Room;
import cz.cuni.mff.abacs.burglar.logics.objects.agents.Agent;
import cz.cuni.mff.abacs.burglar.logics.objects.agents.Burglar;
import cz.cuni.mff.abacs.burglar.logics.objects.agents.Guard;
import cz.cuni.mff.abacs.burglar.logics.objects.items.Item;
import cz.cuni.mff.abacs.burglar.logics.objects.positions.Position;
import cz.cuni.mff.abacs.burglar.logics.planning.instructions.Instruction;
import java.util.List;


/**
 * Interface that masks some implementation details of the level objects.
 * 
 * Objects out of the cz.cuni.mff.abacs.burglar.logics should be using this interface
 * to access the level objects.
 * 
 * @author abacs
 *
 */
public interface GameMap {
	
	
	/** 
	 * Results of a single instruction execution.
	 * 
	 * Out of use.
	 */
	public static enum StepResult {
		FINISHED,
		IMPORTANT_CHANGE,
		NOTHING
	}
	
	
	/** Movement directions on the map. */
	public static enum Direction {
		NORTH, SOUTH, WEST, EAST, NORTH_WEST, SOUTH_WEST, NORTH_EAST, SOUTH_EAST
	};
	
	
	// -------------------------------------------------------------------------
	// getters:
	
	/**
	 * Returns the position with the selected identifier.
	 * 
	 * @param id unique identifier
	 * @return Position object or null
	 */
	public Position getPosition(int id);
	
	
	/**
	 * Returns the position with the selected node.
	 * 
	 * @param node A* node to find
	 * @return Position object or null
	 */
	public Position getPosition(Node node);
	
	
	/**
	 * Returns the position on the selected coordinates.
	 * 
	 * @param x horizontal
	 * @param y vertical
	 * @return position object or null
	 */
	public Position getPosition(int x, int y);
	
	
	/**
	 * Returns all the positions in the map in a new list.
	 * 
	 * @return list of positions of all types.
	 */
	public List<Position> getPositions();
	
	
	/**
	 * Returns all positions on the map that are marked as operable 
	 * (marked by the function isOperable).
	 * 
	 * @return list of interactive positions.
	 */
	public List<Position> getOperablePositions();
	
	
	/**
	 * Returns the rooms with active guards and cameras.
	 * 
	 * @return list of dangerous room.
	 */
	public List<Room> getTrapRooms();
	
	
	/**
	 * Returns the rooms with active guards and cameras.
	 * 
	 * @return list of dangerous room identifiers.
	 */
	public List<Integer> getTrapRoomIds();
	
	
	/**
	 * Returns all the rooms in the map.
	 * 
	 * @return list of rooms
	 */
	public List<Room> getRooms();
	
	
	/**
	 * Returns all the room identifiers.
	 * 
	 * @return list of room identifiers
	 */
	public List<Integer> getRoomIds();
	
	
	/**
	 * Returns the room with the selected identifier.
	 * 
	 * @param id identifier
	 * @return room object or null
	 */
	public Room getRoom(int id);
	
	
	/**
	 * Returns a list of all items in the level.
	 * 
	 * @return
	 */
	public List<Item> getItems();
	
	
	/**
	 * Returns an item with the selected identifier.
	 * 
	 * @param id identifier
	 * @return item, or null
	 */
	public Item getItem(int id);
	
	
	/**
	 * Returns the full list of agents in the level.
	 * 
	 * @return list of agents
	 */
	public List<Agent> getAgents();
	
	
	/**
	 * Returns the stunned agents from the map.
	 * 
	 * @return list of dazed agents
	 */
	public List<Agent> getPassiveAgents();
	
	
	/**
	 * Returns an agent by it's identifier.
	 * 
	 * @param id identifier
	 * @return agent object or null
	 */
	public Agent getAgent(int id);
	
	
	/**
	 * Returns the single burglar agent from the map.
	 * 
	 * @return the burglar object
	 */
	public Burglar getBurglar();
	
	
	/**
	 * Returns all the guards in the level.
	 * 
	 * @return list of guards.
	 */
	public List<Guard> getGuards();
	
	
	/**
	 * Returns the list of messages that has to be displayed to the player
	 * at the beginning of the level.
	 * 
	 * @return 
	 */
	public List<String> getLevelNotes();
	
	
	// -------------------------------------------------------------------------
	
	
	/**
	 * Returns the objects on the selected coordinates.
	 * 
	 * @param x horizontal
	 * @param y vertical
	 * @return position object or null
	 */
	public List<BaseObject> getObjectsOnPosition(int x, int y);
	
	
	/**
	 * 
	 * @param from
	 * @param to
	 * @return 
	 */
	public Direction getDirection(Position from, Position to);
	
	
	/**
	 * 
	 * @param position
	 * @param direction
	 * @return 
	 */
	public Position getNeighbour(Position position, Direction direction);
	
	
	// -------------------------------------------------------------------------
	
	
	/** 
	 * Returns the number of horizontal game map positions.
	 */
	public int getWidth();
	
	
	/** 
	 * Returns the number of vertical game map positions.
	 */
	public int getHeight();
	
	
	// -------------------------------------------------------------------------
	
	
	/**
	 * How many traps must be placed on the level.
	 */
	public int getRequiredTrapRoomCount();
	
	
	// -------------------------------------------------------------------------
	
	
	/** 
	 * Executes a single step for each agent.
	 * */
	public void executeStep();
	
	
	/**
	 *  Adds the list of instructions to the map.
	 */
	public void addInstructions(List<Instruction> instructions);
	
	
	/**
	 * Empties the instruction lists of all agents.
	 */
	public void clearInstructions();
	
	
	/**
	 * Returns the instruction list for a selected agent. 
	 * 
	 * @param agentId agent identifier.
	 */
	public List<Instruction> getAgentInstructions(int agentId);
	
	
	/**
	 * Returns the instruction list for a selected agent.
	 *  
	 * @param agent agent object
	 */
	public List<Instruction> getAgentInstructions(Agent agent);
	
	
	/**
	 * Compares two instruction lists.
	 * 
	 * @return true if they match.
	 */
	public boolean instructionListsMatch(
			List<Instruction> a,
			List<Instruction> b
	);
	
	
	/**
	 * Decides whether the instructions lead to an active trap (guard or camera).
	 * 
	 * @param list
	 * @return rooms where the instructions will trigger a trap.
	 */
	public List<Room> instructionsLeadToTraps(List<Instruction> list);
	
	
	/**
	 * Agents look around in their room.
	 * 
	 * They may discover new positions in room.
	 * If the positions were already known, it does not change them.
	 * 
	 * @return indicator of new knowledge
	 */
	public boolean lookAround();
	
	
	/** 
	 * Returns whether the map have agents that need replanning.
	 */
	public boolean needsReplanning();
	
	
	/**
	 * Returns the list of agents that require replanning.
	 */
	public List<Agent> getAgentsToReplan();
	
	
	/**
	 * Clears the replanning list. 
	 */
	public void clearAgentsToReplan();
	
	
	/**
	 * Appends agent to the replanning list.
	 * 
	 * @param agent agent to replan for.
	 */
	public void addAgentToReplan(Agent agent);
	
	
	/**
	 * Removes agent from the replanning list.
	 */
	public void removeAgentToReplan(Agent agent);
	
	
	// -------------------------------------------------------------------------
	
	
	/**
	 * Returns the list of positions that are represented by the selected A* nodes.
	 */
	public List<Position> nodesToPositions(List<Node> nodes);
	
	
	// -------------------------------------------------------------------------
	
	
	/**
	 * Returns whether an opposing agent or 
	 * opposing position is currently seeing the burglar.
	 * 
	 * @return true if discovered
	 */
	public boolean isBurglarTrapped();
	
	
}
